/**
 * XTeaKey
 *
 * An ActionScript 3 implementation of the XTea algorithm
 * Copyright (c) 2007 Henri Torgemane
 *
 * See LICENSE.txt for full license information.
 */
package com.hurlant.crypto.symmetric
{
	import com.hurlant.crypto.prng.Random;
	import com.hurlant.util.Memory;

	import flash.utils.ByteArray;


	public class XTeaKey implements ISymmetricKey
	{
		public const NUM_ROUNDS:uint=64;
		private var k:Array;

		public function XTeaKey(a:ByteArray)
		{
			a.position=0;
			k=[a.readUnsignedInt(), a.readUnsignedInt(), a.readUnsignedInt(), a.readUnsignedInt()];
		}

		/**
		 * K is an hex string with 32 digits.
		 */
		public static function parseKey(K:String):XTeaKey
		{
			var a:ByteArray=new ByteArray;
			a.writeUnsignedInt(parseInt(K.substr(0, 8), 16));
			a.writeUnsignedInt(parseInt(K.substr(8, 8), 16));
			a.writeUnsignedInt(parseInt(K.substr(16, 8), 16));
			a.writeUnsignedInt(parseInt(K.substr(24, 8), 16));
			a.position=0;
			return new XTeaKey(a);
		}

		public function getBlockSize():uint
		{
			return 8;
		}

		public function encrypt(block:ByteArray, index:uint=0):void
		{
			block.position=index;
			var v0:uint=block.readUnsignedInt();
			var v1:uint=block.readUnsignedInt();
			var i:uint;
			var sum:uint=0;
			var delta:uint=0x9E3779B9;
			for (i=0; i < NUM_ROUNDS; i++)
			{
				v0+=(((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[sum & 3]);
				sum+=delta;
				v1+=(((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[(sum >> 11) & 3]);
			}
			block.position-=8;
			block.writeUnsignedInt(v0);
			block.writeUnsignedInt(v1);
		}

		public function decrypt(block:ByteArray, index:uint=0):void
		{
			block.position=index;
			var v0:uint=block.readUnsignedInt();
			var v1:uint=block.readUnsignedInt();
			var i:uint;
			var delta:uint=0x9E3779B9;
			var sum:uint=delta * NUM_ROUNDS;
			for (i=0; i < NUM_ROUNDS; i++)
			{
				v1-=(((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[(sum >> 11) & 3]);
				sum-=delta;
				v0-=(((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[sum & 3]);
			}
			block.position-=8;
			block.writeUnsignedInt(v0);
			block.writeUnsignedInt(v1);
		}

		public function dispose():void
		{
			//private var k:Array;
			var r:Random=new Random;
			for (var i:uint=0; i < k.length; i++)
			{
				k[i]=r.nextByte();
				delete k[i];
			}
			k=null;
			Memory.gc();
		}

		public function toString():String
		{
			return "xtea";
		}
	}


}

